<?php

namespace xingchen\adminApi\yii;

use xing\ace\map\ResponseApiMap;
use xing\ace\traits\RbacTrait;
use xing\ace\traits\RenderTrait;
use xing\helper\resource\ReturnHelperBase;
use xing\helper\yii\ReturnHelper;
use xingchen\adminApi\ApiInterface;
use Yii;
use yii\db\ActiveRecord;
use yii\filters\AccessControl;
use yii\filters\auth\HttpBasicAuth;
use yii\filters\auth\HttpBearerAuth;
use yii\web\Response;

class YiiBaseApiController extends \yii\rest\ActiveController implements ApiInterface
{

    public $enableCsrfValidation = false;
    public $fieldsType = [];
    public $pageSize = 20;
    public $adminId;
    public $modelSearchClass = '';


    /**
     * {@inheritdoc}
     */
    public function actions()
    {
        $actions = [
            'index' => [
                'class' => 'yii\rest\IndexAction',
                'modelClass' => $this->modelSearchClass ?: $this->modelClass,
                'checkAccess' => [$this, 'checkAccess'],
                'dataFilter'=>[
                    'class' => 'yii\data\ActiveDataFilter',
                    'searchModel'=> ['class' => $this->modelSearchClass ?: $this->modelClass]
                ],
            ],
            'view' => [
                'class' => 'yii\rest\ViewAction',
                'modelClass' => $this->modelClass ?: $this->modelSearchClass,
                'checkAccess' => [$this, 'checkAccess'],
            ],
            'create' => [
                'class' => 'yii\rest\CreateAction',
                'modelClass' => $this->modelClass ?: $this->modelSearchClass,
                'checkAccess' => [$this, 'checkAccess'],
                'scenario' => $this->createScenario,
            ],
            'update' => [
                'class' => 'yii\rest\UpdateAction',
                'modelClass' => $this->modelClass ?: $this->modelSearchClass,
                'checkAccess' => [$this, 'checkAccess'],
                'scenario' => $this->updateScenario,
            ],
            'delete' => [
                'class' => 'yii\rest\DeleteAction',
                'modelClass' => $this->modelClass ?: $this->modelSearchClass,
                'checkAccess' => [$this, 'checkAccess'],
            ],
            'options' => [
                'class' => 'yii\rest\OptionsAction',
            ],
        ];
        return $actions;
    }

    public function behaviors()
    {
        $behaviors = parent::behaviors();
        $behaviors = yii\helpers\ArrayHelper::merge($behaviors, [
            'authenticator' => [
                'class' => HttpBearerAuth::className(),
            ],

            'access' => [
                'class' => AccessControl::className(),
                'only' => ['create', 'delete', 'index', 'update', 'list', 'Lists-Page'],
                'rules' => [
                    [
                        'allow' => true,
                        'actions' => ['create', 'delete', 'index', 'update', 'list'],
                        'roles' => ['@'],
                    ],
                ],
            ],
        ]);
        return $behaviors;
    }

    public function init()
    {
        // 需要手动增加下面的这几行, 否则前端浏览器会报跨域问题错误, 可能是OPTIONS下没有处理产生的bug
        ReturnHelper::allowOrigin();
        if($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
            exit(ReturnHelper::showJson([]));
        }
        Yii::$app->getResponse()->on(Response::EVENT_BEFORE_SEND, [$this, 'beforeApiSend']);
        if (empty($this->modelClass)) $this->modelClass = $this->modelSearchClass;
        return parent::init();
    }


    public function actionListsPage(int $page = 1)
    {
        $class = $this->modelSearchClass ?: $this->modelClass;
        $searchModel = new $class;
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
        return YiiApiFormat::init()->formatSearchModel($dataProvider);
    }


    public function actionLists(int $page = 1)
    {
        $class = $this->modelSearchClass ?: $this->modelClass;
        $searchModel = new $class;
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
        $pageSize = $dataProvider->getPagination()->pageSize;
        $offset = ($page - 1) * $this->pageSize;
        $list = $dataProvider->query->offset($offset)->limit($pageSize)->all();
        return (new YiiApiFormat)->formatList($list);
    }


    /**
     * 更改数据输出格式
     * 默认情况下输出Json数据
     * 如果客户端请求时有传递$_GET['callback']参数，输入Jsonp格式
     * 请求正确时数据为  {"success":true,"data":{...}}
     * 请求错误时数据为  {"success":false,"data":{"name":"Not Found","message":"页面未找到。","code":0,"status":404}}
     * @param \yii\base\Event $event
     */
    public function beforeApiSend($event)
    {
        /* @var $response \yii\web\Response */
        $response = $event->sender;
//        $response->statusCode = $response->getStatusCode();

        if ($response->statusCode >= 400) {
            /*$code = 0;
            //异常处理
            if (true && $exception = \Yii::$app->getErrorHandler()->exception) {
                $messages = $exception->getMessage();
                $code = $exception->getCode();
            }
            //Model出错了
            if ($response->statusCode == 422) {
                $messages = [];
                foreach ($response->data as $v) {
                    $messages[] = $v['message'];
                }
                $messages = implode(", ", $messages);
                //请求错误时数据为  {"success":false,"data":{"name":"Not Found","message":"页面未找到。","code":0,"status":404}}
                $response->data = [
                    'success' => $response->isSuccessful,
                    'status' => 0,
                    'message' => $messages,
                    'data' => $response->data,
                    'code' => $code,
                ];
            }*/
        } else {
            if (!defined('RETURN_TYPE')) {
                $response->data = ReturnHelper::transformation($response->data);
                $response->data = [
                    'success' => $response->isSuccessful,
                    'status' => 1,
                    'message' => $response->statusText,
                    'data' => $response->data,
                    'code' => 0,
                ];
            }
        }
        return ;
    }

    public function beforeRootSend($event)
    {
        /* @var $response \yii\web\Response */
        $response = $event->sender;
        if ($response->data['data'] ?? null) {
            $response->data['status'] = $response->data['data']['status'];
            $response->data['message'] = $response->data['data']['message'];
            $response->data['code'] = $response->data['data']['code'];
            $response->data['data'] = [];
        }
        return ;
    }

    public function render($view, $params = [])
    {
        foreach ($params as $k => $v) {
            if ($v instanceof ActiveRecord && !empty($v)) {
                return ReturnHelper::error(implode(',', $v->getFirstErrors()), 0);
            }
        }
        return ReturnHelper::returnData($params, 'ok');
    }

    /**
     * 成功返回数据
     * @param $data
     * @param int $code
     * @param string $msg
     * @return mixed
     */
    protected function returnData($data, $code = 0, $msg = '')
    {
//        is_array($data) && (array) $data;
        define('RETURN_TYPE', 'data');
        return ReturnHelper::returnData($data, $msg, 1, $code);
    }


    protected function returnList($list, $msg = 'ok')
    {
//        ReturnHelper::$runTime = time() - $this->runTime;
        define('RETURN_TYPE', 'list');
        return ReturnHelper::returnList($list, $msg = 'ok');
    }

    /**
     * 返回数据
     * @param $return
     * @param string $msg
     * @return array
     */
    protected function returnJson($return, $msg = '')
    {
        return ReturnHelper::returnJson($return, $msg);
    }

    /**
     * 返回统一成功消息
     * @return array
     */
    protected function returnApiSuccess()
    {
        return ReturnHelper::returnData([], '操作成功');
    }
    /**
     * 返回错误信息
     * @param $msg
     * @param int $code
     * @return array
     */
    protected function returnMsg($msg, $code = 0)
    {
        Yii::$app->getResponse()->on(Response::EVENT_BEFORE_SEND, [$this, 'beforeRootSend']);
        return [
            'status' => 1,
            'message' => $msg,
            'code' => $code,
            'data' => [],
        ];
    }
    /**
     * 返回错误信息
     * @param $msg
     * @param int $code
     * @return array
     */
    protected function error($msg, $code = 0)
    {
        Yii::$app->getResponse()->on(Response::EVENT_BEFORE_SEND, [$this, 'beforeRootSend']);
        \Yii::error('msg:' . $msg . '  code: '. $code, __METHOD__);
        return [
            'status' => 0,
            'message' => $msg,
            'code' => $code,
            'data' => [],
        ];
    }
    /**
     * 返回捕获的异常错误
     * @param \Exception $e
     * @param string $category
     * @return array
     * @throws \Exception
     */
    protected function returnExceptionError($e, $category = '')
    {
        $code = $e->getCode();
        $msg = $e->getMessage();
        $response = \Yii::$app->getResponse();
        $response->setStatusCode($code >= 100 && $code < 600 ? $code : 499);

        if (defined('IS_LOCAL') ? IS_LOCAL : YII_DEBUG) throw $e;
        return $this->error($msg, $code);
    }
}
